package com.apestech.framework.file;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import com.apestech.framework.file.BufferFile.KeyText;
import com.apestech.framework.file.KeyStrategy.KeySaveType;
import com.apestech.framework.file.modul.DictPageModul;
import com.apestech.framework.file.modul.IndexModul;
import com.apestech.framework.file.modul.PageModul;
import com.apestech.framework.json.JSON;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.util.FileUtil;
import com.apestech.framework.util.StringUtil;

/**
 * 文件存储的数据字典方式，分为固定行数和根据某一KEY值进行分类存储
 * 获取读写的索引及文件名位置 
 * @author hupo
 *
 */
public class FileDictionary extends StringUtil{
	
	public enum LogSaveType {
		COUNT(0),  //记录数 
		KEY(1);    //关键字
	      
	    int value;  
	      
	    LogSaveType(int value) {  
	        this.value = value;  
	    }  
	      
	    public int getValue() {  
	        return value;  
	    }  
	}
	
	private String saveDir="d:/";
	private int fetchSize=100;   //固定页数
	private LogSaveType savetype;
	private DictPageModul keyPage=null;
	private PageModul page=null;
	
	public FileDictionary(int fetchSize, LogSaveType savetype){
		this.fetchSize=fetchSize;
		setSaveType(savetype);
		getPageModul();
	}
	
	public FileDictionary(int fetchSize, LogSaveType savetype, KeySaveType keySaveType){
		this.fetchSize=fetchSize;
		setSaveType(savetype);
		getPageModul();
	}
	
	public void setFetchSize(int fetchSize){
		this.fetchSize=fetchSize;
		if(this.page!=null){
			this.page.setFetchSize(fetchSize);
		}
		if(this.keyPage!=null){
			this.keyPage.setFetchSize(fetchSize);
		}
	}
	
	public int getFetchSize(){
		if(this.fetchSize<=0){
			this.fetchSize=100;
		}
		return this.fetchSize;
	}
	
	public void setSaveType(LogSaveType savetype){
		getFetchSize();
		this.savetype=savetype;
	}
	
	public LogSaveType getSaveType(){
		return this.savetype;
	}
	
	public void clear(){
		this.keyPage=null;
		this.page=null;
		getPageModul();
	}
	
	public int size(){
		if(this.savetype==LogSaveType.COUNT){
			if(this.page==null) return 0;
			return this.page.getCount();
		} else {
			if(this.keyPage==null) return 0;
			return this.keyPage.getCount();
		}
	}
	
	public String getsaveDir(){
		return this.saveDir;
	}
	
	public void setsaveDir(String saveDir){
		this.saveDir=saveDir;
	}
	
	private void getPageModul(){
		if(this.savetype==LogSaveType.COUNT){
			this.page=new PageModul(this.fetchSize);
		} else {
			this.keyPage=new DictPageModul(this.fetchSize);
		}
	}
	
	public void addPage(int row){
		if(this.savetype==LogSaveType.COUNT){
			this.page.addPage(row);
		}
	}
	
	public void addPage(String key, int row){
		if(this.savetype==LogSaveType.KEY){
			this.keyPage.addPage(key, row);
		}
	}
	
	public void addRow(){
		if(this.savetype==LogSaveType.COUNT){
			this.page.addRow();
		}
	}
	
	public void addRow(String key){
		if(this.savetype==LogSaveType.KEY){
			this.keyPage.addRow(key);
		}
	}
	
	public void insRow(){
		if(this.savetype==LogSaveType.COUNT){
			this.page.insRow();
		}
	}
	
	public void insRow(String key){
		if(this.savetype==LogSaveType.KEY){
			this.keyPage.insRow(key);
		}
	}
	
	public void delRow(int index){
		if(this.savetype==LogSaveType.COUNT){
			this.page.removeRow(index);
		} else {
			//this.keyPage.removeRow(key, index);
		}
	}
	
	public int fileCount(){
		if(this.savetype==LogSaveType.COUNT){
			return this.page.getFileCount();
		} else {
			return this.keyPage.getFileCount();
		}
	}
	
	public IndexModul getFileIndex(int index){
		IndexModul p;
		if(this.savetype==LogSaveType.COUNT){
			p=this.page.getFileIndex(index);
		} else {
			p=this.keyPage.getFileIndex(index);
		}
		return p;
	}
	
	public String getFilename(int index) throws Exception {
		String filename="";
		IndexModul p=getFileIndex(index);
		if(this.savetype==LogSaveType.COUNT){
			filename=this.saveDir+"/"+(p.getFileIndex())+".txt";
		} else {
			filename=this.saveDir+"/"+p.getKey()+"/"+(p.getFileIndex())+".txt";
		}
		return FileUtil.getFileNameForSys(filename);
	}	
	
	public String getFilename(KeyText text, int index) throws Exception {
		String filename="";
		IndexModul p;
		if(this.savetype==LogSaveType.KEY){
			p=this.keyPage.getFileIndex((String)text.key, index);
			filename=this.saveDir+"/"+(String)text.key+"/"+(p.getFileIndex())+".txt";
		}
		return FileUtil.getFileNameForSys(filename);
	}
	
	public int getKeyStart(String key){
		if(keyPage==null) return 0;
		return this.keyPage.getKeyStart(key);
	}
	
	public int getKeyEnd(String key){
		if(keyPage==null) return 0;
		return this.keyPage.getKeyEnd(key);
	}
	
	public int getKeyFileCount(String key){
		return this.keyPage.getKeyFileCount(key);
	}
	
	public JSONObject initIndexMap() throws Exception{
		String sfile=FileUtil.getFileNameForSys(this.saveDir+"/index.txt");
		BufferedReader read = new BufferedReader(new FileReader(FileUtil.newFile(sfile)));
		String text=read.readLine();
		read.close();
		read=null;
		if(text==null) return null;
		JSONObject map=JSON.toJSON(text);
		return map;
	}
	
	public void initFile() throws Exception{
		ArrayList<String> list=FileUtil.getDirFirstDir(this.saveDir);
		int len=list.size();
		if(len>0){
			this.savetype=LogSaveType.KEY;
			clear();
			for(int i=0; i<len; i++){
				iniFileInfo(this.saveDir+"/"+list.get(i)+"/", list.get(i));
			}
		} else {
			clear();
			iniFileInfo(this.saveDir+"/", null);
		}
	}
	
	private void iniFileInfo(String dir, String key) throws Exception{
		int len=FileUtil.getMaxFileOrder(dir);
		for(int i=0; i<=len; i++){
			int inx=getFileRowCount(dir+i+".txt");
			if(this.fetchSize<inx){
				this.fetchSize=inx;
			}
			if(key==null){
				this.addPage(inx);
			} else {
				this.addPage(key, inx);
			}
		}
		setFetchSize(this.fetchSize);
	}
	
	private int getFileRowCount(String fName) throws Exception{
		int i=0;
		BufferedReader read = new BufferedReader(new FileReader(FileUtil.getFileNameForSys(fName)));
		while(read.readLine()!=null){
			i++;
		}
		read.close();
		read=null;
		return i;
	}
	
	//先测试写，再测试读，测试读时，对应获取文件名的修改思路要包一层根据KEY自动返回
	//获取实际文件列表，并初始化对应COUNT及KEY相关信息，明确目录同一时间来触发该计算
	//引入KEY的输入 点
	//根据索引及文本内容，获取对应文件名，注意要解决防止文件名重复计算问题
	
	public String toString(){
		if(this.savetype==LogSaveType.KEY){
			return this.keyPage.toString();
		} else {
			return this.page.toString();
		}
	}
	
	public ArrayList<String> getKeyList(){
		if(this.savetype==LogSaveType.KEY){
			return this.keyPage.getKeyList();
		}
		return null;
	}
	
	public String getFileIndexString(int index){
		if(this.savetype==LogSaveType.KEY){
			return this.keyPage.getFileIndexString(index);
		} else {
			return this.page.getFileIndexString(index);
		}
	}
	
	public JSONObject toJSON(){
		JSONObject map=new JSONObject();
		map.put("fetchSize", this.fetchSize);
		map.put("savetype", savetype);
		if(this.keyPage!=null){
			map.put("keyPage", this.keyPage.toJSON());
		}
		if(this.page!=null){
			map.put("page", this.page.toJSON());
		}
		return map;
	}
	
	public void fromJSON(JSONObject map) throws Exception{
		if(map==null) return;
		this.fetchSize=(int) map.get("fetchSize");
		String type=(String) map.get("savetype");
		if(type.equals("KEY")){
			this.savetype=LogSaveType.KEY;
		} else {
			this.savetype=LogSaveType.COUNT;
		}
		getPageModul();
		JSONObject pmap=map.getJSONObject("keyPage");
		if(pmap!=null){
			this.keyPage.fromJSON(pmap);
		}
		pmap=map.getJSONObject("page");
		if(pmap!=null){
			this.page.fromJSON(pmap);
		}
	}
	
}
